package ru.dveriwell.intra.finplan.ui;

import java.math.BigDecimal;
import java.util.Calendar;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.ldap.userdetails.InetOrgPerson;

import ru.dveriwell.intra.finplan.domain.Plandivision;
import ru.dveriwell.intra.finplan.domain.Planperiod;
import ru.dveriwell.intra.finplan.domain.Planrequest;
import ru.dveriwell.intra.finplan.domain.Planunit;
import ru.dveriwell.intra.finplan.domain.Planuser;
import ru.dveriwell.intra.finplan.domain.Planuserdivision;
import ru.dveriwell.intra.finplan.ui.vo.UIRequest;
import ru.dveriwell.intra.util.DataBindingException;
import ru.dveriwell.intra.util.UserHierarchicalBeanContainer;

import com.vaadin.data.Container;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Field;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Table;
import com.vaadin.ui.TableFieldFactory;
import com.vaadin.ui.TextField;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.VerticalLayout;

/**
 * @author KompaniecS
 * 
 */
public class RequesterTabComposition extends CustomComponent {

	private ComboBox periodComboBox;
	private ComboBox divisionComboBox;
	private TreeTable requestTreeTable;
//	private Table requestTreeTable;

	private EntityManager entityManager;
	private UserHierarchicalBeanContainer<Integer, UIRequest> requestContainer;
	private BeanContainer<Integer, Planperiod> periodContainer;
	private BeanContainer<Integer, Plandivision> divisionContainer;

	private static final long serialVersionUID = -171959703722724097L;

	public RequesterTabComposition() {
		buildMainLayout();
		AddListeners();
	}

	public void bindData(EntityManager entityManager)
			throws DataBindingException {

		this.entityManager = entityManager;

		// Получение коллекции периодов планирования
		TypedQuery<Planperiod> periodQuery = entityManager
				.createQuery("select pp from Planperiod pp order by pp.id",
						Planperiod.class);
		periodContainer = new BeanContainer<Integer, Planperiod>(
				Planperiod.class);
		periodContainer.setBeanIdProperty("id");
		periodContainer.addAll(periodQuery.getResultList());
		periodComboBox.setContainerDataSource(periodContainer);
		periodComboBox.setItemCaptionPropertyId("periodname");

		// Выбор текущего периода по умолчанию
		for (int periodId : periodContainer.getItemIds()) {
			if (periodContainer.getItem(periodId).getBean().getPeriodend()
					.after(Calendar.getInstance().getTime())) {
				periodComboBox.select(periodId);
				break;
			}

		}

		// Получение объекта пользователя
		TypedQuery<Planuser> userQuery = entityManager
				.createQuery(
						"select puser from Planuser puser where lower(puser.ssamaccountname) = lower(:username)",
						Planuser.class);
		userQuery.setParameter("username",
				((InetOrgPerson) SecurityContextHolder.getContext()
						.getAuthentication().getPrincipal()).getUsername());
		Planuser myUser = userQuery.getSingleResult();

		if (null == myUser)
			throw new DataBindingException("User not found!");

		// Получение коллекции доступных пользователю подразделений
		if (myUser.getPlanuserdivisions().size() > 0) {

			divisionContainer = new BeanContainer<Integer, Plandivision>(
					Plandivision.class);
			divisionContainer.setBeanIdProperty("id");
			divisionComboBox.setContainerDataSource(divisionContainer);
			divisionComboBox.setItemCaptionPropertyId("divisionname");

			for (Planuserdivision pud : myUser.getPlanuserdivisions())
				divisionContainer.addBean(pud.getPlandivision());

		} else {
			divisionComboBox.addItem("Нет доступных подразделений");
		}
		divisionComboBox.setValue(divisionContainer.getIdByIndex(1));

		BindRequestTableData();

	}

	public void BindRequestTableData() {

		// Таблица заявок, превый этап - получение всех статей расходов
		TypedQuery<Planunit> getUnitsQuery = entityManager.createQuery(
				"select pu from Planunit pu order by pu.unitcode, pu.unitname",
				Planunit.class);

		// Таблица заявок, второй этап - получение имеющихся заявок
		TypedQuery<Planrequest> getRequestQuery = entityManager
				.createQuery(
						"select pr from Planrequest pr where pr.planperiod=:period and pr.plandivision=:division",
						Planrequest.class);
		getRequestQuery.setParameter("period",
				periodContainer.getItem(periodComboBox.getValue()).getBean());
		getRequestQuery.setParameter("division",
				divisionContainer.getItem(divisionComboBox.getValue())
						.getBean());

		// Таблица заявок, заполнение контейнера заявок статьями
		requestContainer = new UserHierarchicalBeanContainer<Integer, UIRequest>(
				UIRequest.class, "parentid");
		requestContainer.setBeanIdProperty("id");
		for (Planunit pu : getUnitsQuery.getResultList())
			requestContainer.addBean(new UIRequest(pu, new Planrequest()));

		// Таблица заявок, добавление имеющихся заявок в контейнер
		for (Planrequest pr : getRequestQuery.getResultList()) {
			requestContainer.getItem(pr.getPlanunit().getId()).getBean()
					.setRequest(pr);
		}

		RecalcRequestTotals();
		
		requestTreeTable.setContainerDataSource(requestContainer);
		requestTreeTable.setHierarchyColumn("commonname");
		String visibleColumns[] = { "commonname", "requestqty",
				"requestcomment" };
		String columnHeaders[] = { "Статья", "Количество", "Комментарий" };
		requestTreeTable
				.setColumnHeaderMode(com.vaadin.ui.Table.COLUMN_HEADER_MODE_EXPLICIT);
		requestTreeTable.setVisibleColumns(visibleColumns);
		requestTreeTable.setColumnHeaders(columnHeaders);
//		requestTreeTable.setSelectable(true);
//		requestTreeTable.setReadThrough(true);
		requestTreeTable.setEditable(true);

	}

	private void RecalcRequestTotals() {
		
		System.out.println(Calendar.getInstance().getTime().toString() + ": Пересчет итогов по таблице...");

		// обнуление итогов по дереву
		for (int i = 0; i < requestContainer.size(); i++) {
//			if (requestContainer.hasChildren())
//			System.out.println(Calendar.getInstance().getTime().toString() + ": commonname: " + 
//					requestContainer.getItem(requestContainer.getIdByIndex(i)).getBean().getCommonname() + ", unitcode: " +
//					requestContainer.getItem(requestContainer.getIdByIndex(i)).getBean().getUnitcode());
			if (null != requestContainer.getItem(requestContainer.getIdByIndex(i)).getBean().getUnitcode())
				requestContainer.getItem(requestContainer.getIdByIndex(i)).getBean().setRequestqty(new BigDecimal(0));
		}
		
		// рекурсивное суммирование уровня дерева
		for (int i = 0; i < requestContainer.size(); i++) {
			// if
			// (!requestContainer.hasChildren(requestContainer.getIdByIndex(i)))
			if (null == requestContainer
					.getItem(requestContainer.getIdByIndex(i)).getBean()
					.getUnitcode())
				AddSummToParent(
						requestContainer.getIdByIndex(i),
						requestContainer
								.getItem(requestContainer.getIdByIndex(i))
								.getBean().getRequestqty());
		}

	}
	
	private void AddSummToParent(Object itemId, BigDecimal n) {
		
		if (null == requestContainer.getParent(itemId)) 
			return;
		
		if (n.equals(new BigDecimal(0)))
			return;
		
		int parentId = (Integer) requestContainer.getParent(itemId);
		BigDecimal parentSum = requestContainer.getItem(parentId).getBean().getRequestqty();
//		requestContainer.getItem(requestContainer.getParent(itemId)).getBean().setRequestqty(parentSum.add(n));

		System.out.println(Calendar.getInstance().getTime().toString() + 
				": Adding " + n + " to " + parentSum + " in " +
				requestContainer.getItem(parentId).getBean().getCommonname() + " (id " + parentId + ")");

		requestContainer.getItem(parentId).getItemProperty("requestqty").setValue(parentSum.add(n));
		
		// рекурсивный вызов суммирования родительской статьи
		AddSummToParent(requestContainer.getParent(itemId), n);
		
	}

	@SuppressWarnings("serial")
	private void AddListeners() {

		periodComboBox.addListener(new BlurListener() {

			@Override
			public void blur(BlurEvent event) {
				BindRequestTableData();
			}
		});

		divisionComboBox.addListener(new BlurListener() {

			@Override
			public void blur(BlurEvent event) {
				BindRequestTableData();
			}
		});
		
		requestTreeTable.setTableFieldFactory(new TableFieldFactory() {

			@Override
			public Field createField(Container container, Object itemId,
					Object propertyId, Component uiContext) {

				if (null != requestContainer.getItem(itemId).getBean()
						.getUnitcode())
					return null;

				if (propertyId.toString().equals("requestqty")) {
					final TextField newTxt = new TextField();
					newTxt.setImmediate(true);
					newTxt.addListener(new ValueChangeListener() {
						@Override
						public void valueChange(ValueChangeEvent event) {
							System.out.println(Calendar.getInstance().getTime()
									.toString()
									+ ": valueChangeListener " + this.toString() + " called");
							RecalcRequestTotals();
							// requestTreeTable.requestRepaintAll();
						}
					});
					return newTxt;
				}
					

				if (propertyId.toString().equals("requestcomment"))
					return new TextField();

				return null;
			}
		});

	}

	private HorizontalLayout buildMainLayout() {
		// common part: create layout
		HorizontalLayout mainLayout = new HorizontalLayout();
		mainLayout.setImmediate(false);
		// mainLayout.setWidth("100%");
		// mainLayout.setHeight("100%");
		mainLayout.setMargin(false);

		// top-level component properties
		// setWidth("100.0%");
		// setHeight("100.0%");

		VerticalLayout filtersColumn = new VerticalLayout();
		filtersColumn.setMargin(true);

		// periodComboBox
		periodComboBox = new ComboBox();
		periodComboBox.setCaption("Период");
		periodComboBox.setImmediate(true);
		periodComboBox.setWidth("160px");
		filtersColumn.addComponent(periodComboBox);

		// divisionComboBox
		divisionComboBox = new ComboBox();
		divisionComboBox.setCaption("Подразделение");
		divisionComboBox.setImmediate(true);
		divisionComboBox.setWidth("160px");
		filtersColumn.addComponent(divisionComboBox);

		// requestTreeTable
		requestTreeTable = new TreeTable();
//		requestTreeTable = new Table();
		requestTreeTable.setCaption("Заявки");
		requestTreeTable.setImmediate(true);
		requestTreeTable.setWidth("100%");
		requestTreeTable.setHeight("100%");

		VerticalLayout tableColumn = new VerticalLayout();
		tableColumn.setMargin(true);

		tableColumn.addComponent(requestTreeTable);
		
		//DEBUG
		Button testBtn = new Button("Fuck the things up");
		testBtn.addListener(new ClickListener() {

			@Override
			public void buttonClick(ClickEvent event) {
				System.out.println(Calendar.getInstance().getTime().toString() + 
						": Setting requestqty=666 to " +
						requestContainer.getItem(43).getBean().getCommonname());
				requestContainer.getItem(43).getItemProperty("requestqty").setValue(new BigDecimal(666));
			}});
		
		tableColumn.addComponent(testBtn);

		mainLayout.addComponent(filtersColumn);
		mainLayout.addComponent(tableColumn);

		setCompositionRoot(mainLayout);

		return mainLayout;

	}

}
